using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using Microsoft.Xna.Framework;

namespace Oops.Xna.Framework
{
	/// <summary>
	/// Provides the base class for a generic collection of <see cref="Microsoft.Xna.Framework.IGameComponent"/> instances.
	/// </summary>
	/// <typeparam name="T">The type of items in the collection.</typeparam>
	public class GameComponentCollection<T> : Collection<T> where T : IGameComponent
	{
		/// <summary>
		/// Raised when a component is added to the <see cref="GameComponentCollection&lt;T&gt;"/>.
		/// </summary>
		public event EventHandler<GameComponentCollectionEventArgs<T>> ComponentAdded;

		/// <summary>
		/// Raised when a component is removed from the <see cref="GameComponentCollection&lt;T&gt;"/>.
		/// </summary>
		public event EventHandler<GameComponentCollectionEventArgs<T>> ComponentRemoved;

		private GameComponentCollectionEventArgs<T> eventArgs = new GameComponentCollectionEventArgs<T>();

		#region Collection<T> Members

		protected override void ClearItems()
		{
			// Notify subscribers of removed components.
			for (int i = 0; i < this.Count; i++)
			{
				this.eventArgs.Item = this.Items[i];
				this.OnComponentRemoved(this.eventArgs);
			}

			// Call inherited method.
			base.ClearItems();
		}

		protected override void InsertItem(int index, T item)
		{
			// The item being added must not be in the collection already.
			if (base.IndexOf(item) != -1)
			{
				throw new ArgumentException("Resources.CannotAddSameComponentMultipleTimes");
			}

			// Call inherited method.
			base.InsertItem(index, item);

			// Notify subscribers of added component.
			if (item != null)
			{
				this.eventArgs.Item = item;
				this.OnComponentAdded(this.eventArgs);
			}
		}

		protected override void RemoveItem(int index)
		{
			// Get the item at the specified index.
			T item = base[index];

			// Call inherited method.
			base.RemoveItem(index);

			// Notify subscribers of removed component.
			if (item != null)
			{
				this.eventArgs.Item = item;
				this.OnComponentRemoved(this.eventArgs);
			}
		}

		protected override void SetItem(int index, T item)
		{
			// Setting items is not supported.
			throw new NotSupportedException("Resources.CannotSetItemsIntoGameComponentCollection");
		}

		#endregion

		protected virtual void OnComponentAdded(GameComponentCollectionEventArgs<T> e)
		{
			// Notify subscribers of added component.
			if (this.ComponentAdded != null)
			{
				this.ComponentAdded(this, e);
			}
		}

		protected virtual void OnComponentRemoved(GameComponentCollectionEventArgs<T> e)
		{
			// Notify subscribers of removed component.
			if (this.ComponentRemoved != null)
			{
				this.ComponentRemoved(this, e);
			}
		}
	}
}
